/*
 * Copyright (C) 2012-2013 Michael L.R. Marques
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * Contact: michaellrmarques@gmail.com
 */

package com.jm.commons.components.help;

import com.jm.commons.components.editor.HtmlPageEvent;
import com.jm.commons.components.editor.HtmlPageListener;
import com.jm.commons.components.help.models.HelpListModel;
import com.jm.commons.components.help.models.HelpSearchListModel;
import com.jm.commons.components.help.models.HelpTreeModel;
import com.jm.commons.components.help.objects.HelpFile;
import com.jm.commons.components.help.renderers.HelpListCellRenderer;
import com.jm.commons.components.help.renderers.HelpTreeCellRenderer;
import com.jm.commons.fio.FileSystem;
import java.awt.event.MouseEvent;
import java.awt.print.PrinterException;
import java.io.File;
import java.io.Serializable;
import javax.swing.JPanel;

/**
 * Help Component which displays hyper-text help files and content
 * in a directory format
 * 
 * Help.java
 * @autor Michael L.R. Marques
 * Created on 07 Jan 2011, 8:45:06 AM
 */
public class Help extends JPanel implements Serializable {
    
    /**
     * Initial page property support constant
     */
    public static final String PROP_INITIAL_PAGE_PROPERTY = "initialPage";
    
    /**
     * Directory property support constant
     */
    public static final String PROP_DIRECTORY_PROPERTY = "directory";
    
    /**
     * Initial page property
     */
    private File initialPage;
    
    /**
     * Directory property
     */
    private File directory;
    
    /**
     * Help JavaBean constructor
     */
    public Help() {
        initComponents();
        this.helpTree.setCellRenderer(HelpTreeCellRenderer.getInstance());
        this.indexList.setCellRenderer(HelpListCellRenderer.getInstance());
        this.searchList.setCellRenderer(HelpListCellRenderer.getInstance());
        this.helpViewer.addHtmlViewerListner(new HtmlPageListener() {
            @Override public void pageOpening(HtmlPageEvent e) {
                btnBack.setEnabled(helpViewer.canGoBack());
                btnForward.setEnabled(helpViewer.canGoForward());
            }
            @Override public void pageOpened(HtmlPageEvent e) {
                btnBack.setEnabled(helpViewer.canGoBack());
                btnForward.setEnabled(helpViewer.canGoForward());
            }
            @Override public void pageBack(HtmlPageEvent e) {
                btnBack.setEnabled(helpViewer.canGoBack());
                btnForward.setEnabled(helpViewer.canGoForward());
            }
            @Override public void pageForward(HtmlPageEvent e) {
                btnBack.setEnabled(helpViewer.canGoBack());
                btnForward.setEnabled(helpViewer.canGoForward());
            }
        });
    }
    
    /**
     * Initial page get property
     * 
     * @return 
     */
    public File getInitialPage() {
        return this.initialPage;
    }
    
    /**
     * Initial page set property
     * Checks if the page exists
     * Then sets the page
     * 
     * @param file 
     */
    public void setInitialPage(File initialPage) {
        // Check if the initial page is valid
        if (initialPage == null ||
                !initialPage.exists() ||
                    !initialPage.isFile() ||
                        !FileSystem.isValidExtension(initialPage, HelpFile.getExtensions())) {
            return;
        }
        // Fire the property change event
        super.firePropertyChange(PROP_INITIAL_PAGE_PROPERTY, this.initialPage, initialPage);
        // Set the initial page
        this.initialPage = initialPage;
        this.helpViewer.setPage(this.initialPage);
    }
    
    /**
     * Gets the directory file property
     * 
     * @return @code{File}
     */
    public File getDirectory() {
        return this.directory;
    }
    
    /**
     * Sets the directory file property
     * 
     * @param directory 
     */
    public void setDirectory(File directory) {
        // Check if the directory is valid
        if (directory == null ||
                !directory.exists() ||
                    !directory.isDirectory()) {
            return;
        }
        // Fire the property change event
        super.firePropertyChange(PROP_DIRECTORY_PROPERTY, this.directory, directory);
        // Set the directory
        this.directory = directory;
        this.helpTree.setModel(new HelpTreeModel(new HelpFile(this.directory)));
        this.indexList.setModel(new HelpListModel(new HelpFile(this.directory)));
    }
            
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jToolBar1 = new javax.swing.JToolBar();
        btnBack = new javax.swing.JButton();
        btnForward = new javax.swing.JButton();
        btnPrint = new javax.swing.JButton();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        helpViewer = new com.jm.commons.components.editor.JMEditorPane();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jScrollPane2 = new javax.swing.JScrollPane();
        helpTree = new javax.swing.JTree();
        jPanel2 = new javax.swing.JPanel();
        btnSearch = new javax.swing.JButton();
        chbCaseSensitive = new javax.swing.JCheckBox();
        jScrollPane4 = new javax.swing.JScrollPane();
        searchList = new javax.swing.JList();
        chbRegex = new javax.swing.JCheckBox();
        txtSearch = new com.jm.commons.components.textfield.HintJTextField();
        chbInside = new javax.swing.JCheckBox();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        indexList = new javax.swing.JList();

        jToolBar1.setFloatable(false);
        jToolBar1.setRollover(true);
        jToolBar1.setOpaque(false);

        btnBack.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/commons/components/help/icons/back.png"))); // NOI18N
        btnBack.setToolTipText("Back");
        btnBack.setEnabled(false);
        btnBack.setFocusable(false);
        btnBack.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnBack.setOpaque(false);
        btnBack.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnBack.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                Back(evt);
            }
        });
        jToolBar1.add(btnBack);

        btnForward.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/commons/components/help/icons/foreward.png"))); // NOI18N
        btnForward.setToolTipText("Foreward");
        btnForward.setEnabled(false);
        btnForward.setFocusable(false);
        btnForward.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnForward.setOpaque(false);
        btnForward.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnForward.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                Forward(evt);
            }
        });
        jToolBar1.add(btnForward);

        btnPrint.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/commons/components/help/icons/print.png"))); // NOI18N
        btnPrint.setToolTipText("Print");
        btnPrint.setFocusable(false);
        btnPrint.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnPrint.setOpaque(false);
        btnPrint.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnPrint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                Print(evt);
            }
        });
        jToolBar1.add(btnPrint);

        jSplitPane1.setDividerLocation(200);

        helpViewer.setEditable(false);
        helpViewer.setContentType("text/html"); // NOI18N
        helpViewer.addHyperlinkListener(new javax.swing.event.HyperlinkListener() {
            public void hyperlinkUpdate(javax.swing.event.HyperlinkEvent evt) {
                hyperlinkSelected(evt);
            }
        });
        jScrollPane1.setViewportView(helpViewer);

        jSplitPane1.setRightComponent(jScrollPane1);

        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        helpTree.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        helpTree.setShowsRootHandles(true);
        helpTree.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                helpFileSelected(evt);
            }
        });
        jScrollPane2.setViewportView(helpTree);

        jTabbedPane1.addTab("Help", jScrollPane2);

        btnSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/commons/components/help/icons/search.png"))); // NOI18N
        btnSearch.setContentAreaFilled(false);
        btnSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                Search(evt);
            }
        });

        chbCaseSensitive.setText("Case-Sensitive");

        searchList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                helpFileSelected(evt);
            }
        });
        jScrollPane4.setViewportView(searchList);

        chbRegex.setText("Regular Expressions");

        txtSearch.setHintText("Search...");
        txtSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                Search(evt);
            }
        });

        chbInside.setText("Check in Document");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                        .addComponent(txtSearch, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(chbRegex, javax.swing.GroupLayout.DEFAULT_SIZE, 174, Short.MAX_VALUE)
                    .addComponent(chbCaseSensitive, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(chbInside, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(txtSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(chbCaseSensitive, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(chbRegex, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(chbInside, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(12, 12, 12)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE)
                .addContainerGap())
        );

        jTabbedPane1.addTab("Search", jPanel2);

        indexList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                helpFileSelected(evt);
            }
        });
        jScrollPane3.setViewportView(indexList);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Index", jPanel1);

        jSplitPane1.setLeftComponent(jTabbedPane1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(10, 10, 10)
                .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE)
                .addGap(10, 10, 10))
            .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void Back(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_Back
        if (this.helpViewer.canGoBack()) {
            this.helpViewer.back();
        }
	}//GEN-LAST:event_Back

	private void Forward(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_Forward
		if (this.helpViewer.canGoForward()) {
			this.helpViewer.forward();
		}
	}//GEN-LAST:event_Forward

    private void Print(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_Print
        try {
            this.helpViewer.print();
        } catch (PrinterException pe) {
            pe.printStackTrace();
        }
	}//GEN-LAST:event_Print

    private void helpFileSelected(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_helpFileSelected
        if (evt.getButton() == MouseEvent.BUTTON1) {
            if (evt.getSource() instanceof javax.swing.JTree) {
                if (this.helpTree.getLastSelectedPathComponent() != null &&
                        ((HelpFile) this.helpTree.getLastSelectedPathComponent()).isFile()) {
                    this.helpViewer.setPage(((HelpFile) this.helpTree.getLastSelectedPathComponent()).getURL());
                }
            } else if (evt.getSource() instanceof javax.swing.JList) {
                if (evt.getSource().equals(this.indexList)) {
                    if (this.indexList.getSelectedValue() != null) {
                        this.helpViewer.setPage(((HelpFile) this.indexList.getSelectedValue()).getURL());
                    }
                } else if (evt.getSource().equals(this.searchList)) {
                    if (this.searchList.getSelectedValue() != null) {
                        this.helpViewer.setPage(((HelpFile) this.searchList.getSelectedValue()).getURL());
                    }
                }
            }
        }
	}//GEN-LAST:event_helpFileSelected
    
	private void Search(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_Search
            if (!this.txtSearch.getText().isEmpty() &&
                            !this.txtSearch.getText().equals(this.txtSearch.getHintText())) {
                    this.searchList.setModel(new HelpSearchListModel(new HelpFile(this.directory), this.txtSearch.getText(), this.chbCaseSensitive.isSelected(), this.chbRegex.isSelected(), this.chbInside.isSelected()));
            }
	}//GEN-LAST:event_Search

	private void hyperlinkSelected(javax.swing.event.HyperlinkEvent evt) {//GEN-FIRST:event_helpViewerHyperlinkUpdate
            this.helpViewer.setPage(evt.getURL());
	}//GEN-LAST:event_helpViewerHyperlinkUpdate


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnBack;
    private javax.swing.JButton btnForward;
    private javax.swing.JButton btnPrint;
    private javax.swing.JButton btnSearch;
    private javax.swing.JCheckBox chbCaseSensitive;
    private javax.swing.JCheckBox chbInside;
    private javax.swing.JCheckBox chbRegex;
    private javax.swing.JTree helpTree;
    private com.jm.commons.components.editor.JMEditorPane helpViewer;
    private javax.swing.JList indexList;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JList searchList;
    private com.jm.commons.components.textfield.HintJTextField txtSearch;
    // End of variables declaration//GEN-END:variables

}